package com.rectcircle.wechat.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;

import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import com.rectcircle.wechat.msg.vo.Message;
import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;

/**
 * 
 * xml处理器将XML与Message之间互转<br>
 * 底层使用jaxb实现
 * 
 * @author RectCircle
 * @version 0.1<br>
 * 2016年7月18日-上午12:05:11<br>
 * Copyright (c) 2016 RectCircle-版权所有<br>
 *
 */
@SuppressWarnings("restriction")
public class XmlHandler {
	
	/**
	 * 
	 * 根据实体对象生成xml字符串
	 * 
	 * @param msg 后台创建的用于回复的消息对象，或任意消息对象
	 * @return xml格式的字符串
	 */
	public static String createXml(Message msg) {
		if(msg==null)
			throw new NullPointerException("消息不能为null类型");
		JAXBContext context = null;
		StringWriter writer = null;
		try {
			context = JAXBContext.newInstance(Message.class);
			Marshaller marshaller = context.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");// //编码格式
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);// 是否格式化生成的xml串
			marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);// 是否省略xm头声明信息
			// 由于对必需的库 D:\IDE\Java\jdk8u60\jre\lib\rt.jar 具有一定限制,因此无法访问
			// 不对字符进行转义
			marshaller.setProperty("com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler",
					new CharacterEscapeHandler() {
						@Override
						public void escape(char[] ch, int start, int length, boolean isAttVal, Writer writer)
								throws IOException {
							writer.write(ch, start, length);
						}
					});

			writer = new StringWriter();
			marshaller.marshal(msg, writer);
		} catch (JAXBException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return writer.toString();
	}

	/**
	 * 当将微信服务器将POST消息的XML数据包到开发者填写的URL上时，将XML消息解析为对应的Message对象<br>
	 * 传入HttpServletRequest对象生成Message对象
	 * 
	 * @param request HttpServletRequest对象
	 * @return 生成接收到的消息对象
	 */
	public static Message parseXml(HttpServletRequest request){
	    try {
	    	request.setCharacterEncoding("UTF-8");
			return parseXml(request.getInputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
	    return null;
	}

	/**
	 * 当将微信服务器将POST消息的XML数据包到开发者填写的URL上时，将XML消息解析为对应的Message对象<br>
	 * 根据根据输入流生成Message对象
	 * 
	 * @param in 输入流对象
	 * @return 生成接收到的消息对象
	 */
	public static Message parseXml(InputStream in){
		StringBuffer sb = null;
		BufferedReader br = null;
		try {
			sb = new StringBuffer();
			br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
			String s = null;
			while ((s = br.readLine()) != null) {
				sb.append(s);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(br!=null){
					br.close();					
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return parseXml(sb.toString());
	}

	/**
	 * 当将微信服务器将POST消息的XML数据包到开发者填写的URL上时，将XML消息解析为对应的Message对象<br>
	 * 将xml字符串映射为实体对象
	 * 
	 * @param xmlString 后台接收的任意类型的消息字符串（XML格式）包括自定义菜单事件推送、普通消息、事件推送
	 * @return 返回对应的消息对应的实体对象
	 */
	public static Message parseXml(String xmlString) {
		Message msg = null;
		try {
			JAXBContext context = JAXBContext.newInstance(Message.class);
			Unmarshaller unmarshaller = context.createUnmarshaller();
			msg = (Message) unmarshaller.unmarshal(new StringReader(xmlString));
		} catch (JAXBException e) {
			e.printStackTrace();
			System.err.println(xmlString);
		}
		return msg;
	}

}
